package com.zang.util;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class DateUtil {

    private static final String YEAR_MONTH_DAY = "yyyy-MM-dd";
    private static final String YEAR_MONTH = "yyyy-MM";
    private static final String MONTH_DAY = "M月d日";
    private static final DateTimeFormatter FORMATTER_YM = DateTimeFormatter.ofPattern(YEAR_MONTH);
    private static final DateTimeFormatter FORMATTER_YMD = DateTimeFormatter.ofPattern(YEAR_MONTH_DAY);
    private static final DateTimeFormatter FORMATTER_MD= DateTimeFormatter.ofPattern(MONTH_DAY);

    private DateUtil() {
    }

    /**
     * date 转String
     * 格式 yyyy-MM-dd
     *
     * @param date date
     * @return Date
     */
    public static String dateToString(Date date) {
        return dateToLocalDate(date).toString();
    }

    /**
     * date 转String
     * 格式 yyyy-MM
     *
     * @param date date
     * @return Date
     */
    public static String dateToStringByYearMonth(Date date) {
        return dateToLocalDate(date).format(FORMATTER_YM);
    }

    /**
     * 格式化日期
     * 格式 M月-d日
     *
     * @param date date
     * @return Date
     */
    public static String formatByMonthDay(LocalDate date) {
        return date.format(FORMATTER_MD);
    }


    /**
     * Date to LocalDate
     *
     * @param date date
     * @return Date
     */
    public static LocalDate dateToLocalDate(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalDate();
    }

    /**
     * Date to LocalTime
     *
     * @param date date
     * @return Date
     */
    public static LocalTime dateToLocalTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalTime();
    }

    /**
     * LocalDate to Date
     *
     * @param date date
     * @return Date
     */
    public static Date localDateToDate(LocalDate date) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = date.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * String to LocalDate
     */
    public static LocalDate stringToLocalDate(String date) {
        if (date.length() < 10) {
            date += "-01";
        }
        if (date.length() > 10) {
            date = date.substring(0, 10);
        }
        return LocalDate.parse(date, DateTimeFormatter.ofPattern(YEAR_MONTH_DAY));
    }

    /**
     * Date to LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * LocalDateTime to Date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 获取指定日期
     * @param offset 天
     * @return Date
     */
    public static LocalDate getSpecifiedDay(int offset){
        return LocalDate.now().plusDays(offset);
    }

    /**
     * 获取指定时间年和月
     *
     * @param startDate startDate
     * @return Date yearAndMonth
     */
    public static int[] getYearAndMonth(String startDate, int time) {
        if (startDate.length() < 10) {
            startDate += "-01";
        }
        LocalDate date = LocalDate.parse(startDate, DateTimeFormatter.ofPattern(YEAR_MONTH_DAY));
        LocalDate localDate = null;
        localDate = date.plusYears(time);
        int[] yearAndMonth = new int[2];
        yearAndMonth[0] = localDate.getYear();
        yearAndMonth[1] = localDate.getMonthValue();
        return yearAndMonth;
    }

    /**
     * 获取之前年和月
     *
     * @param startDate startDate
     * @return Date yearAndMonth
     */
    public static int[] getYearAndMonth(String startDate) {
        if (startDate.length() < 10) {
            startDate += "-01";
        }
        LocalDate date = LocalDate.parse(startDate, DateTimeFormatter.ofPattern(YEAR_MONTH_DAY));
        int[] yearAndMonth = new int[2];
        yearAndMonth[0] = date.getYear();
        yearAndMonth[1] = date.getMonthValue();
        return yearAndMonth;
    }

    /**
     * 获取开始结束时间 yyyy-MM-dd
     *
     * @param date date
     * @param type type
     * @return Date
     */
    public static String[] getStartAndEndTimeForYMD(Date date, int type) {
        String[] beginAndEndDate = new String[2];
        LocalDate localDate = dateToLocalDate(date);
        switch (type) {
            case 1:
                beginAndEndDate = getStartAndEndTimeForYMD(date);
                break;
            case 2:
                beginAndEndDate[0] = LocalDate.of(localDate.getYear(), 1, localDate.getDayOfMonth()).toString();
                beginAndEndDate[1] = LocalDate.of(localDate.getYear(), 12, localDate.getDayOfMonth()).toString();
                break;
            default:
                beginAndEndDate[0] = localDate.toString();
                beginAndEndDate[1] = localDate.toString();
                break;
        }
        return beginAndEndDate;
    }

    /**
     * 获取开始结束时间 yyyy-MM
     *
     * @param date date
     * @param type type
     * @return Date
     */
    public static String[] getStartAndEndTimeForYM(Date date, int type) {
        String[] beginAndEndDate = new String[2];
        LocalDate localDate = dateToLocalDate(date);
        switch (type) {
            case 1:
                beginAndEndDate = getStartAndEndTimeForYM(date);
                break;
            case 2:
                beginAndEndDate[0] = LocalDate.of(localDate.getYear(), 1, localDate.getDayOfMonth()).format(FORMATTER_YM).toString();
                beginAndEndDate[1] = LocalDate.of(localDate.getYear(), 12, localDate.getDayOfMonth()).format(FORMATTER_YM).toString();
                break;
            default:
                beginAndEndDate[0] = localDate.format(FORMATTER_YM).toString();
                beginAndEndDate[1] = localDate.format(FORMATTER_YM).toString();
                break;
        }
        return beginAndEndDate;
    }

    /**
     * 获取开始结束时间 yyyy-MM-dd
     *
     * @param date date
     * @return Date
     */
    public static String[] getStartAndEndTimeForYMD(Date date) {
        LocalDate localDate = dateToLocalDate(date);
        String[] beginAndEndDate = new String[2];
        int month = localDate.getMonthValue();
        switch (month % 3) {
            case 1:
                beginAndEndDate[0] = localDate.toString();
                beginAndEndDate[1] = localDate.plusMonths(2).toString();
                break;
            case 2:
                beginAndEndDate[0] = localDate.minusMonths(1).toString();
                beginAndEndDate[1] = localDate.plusMonths(1).toString();
                break;
            default:
                beginAndEndDate[0] = localDate.toString();
                beginAndEndDate[0] = localDate.minusMonths(2).toString();
                break;
        }
        return beginAndEndDate;
    }

    /**
     * 获取开始结束时间 yyyy-MM
     *
     * @param date date
     * @return Date
     */
    public static String[] getStartAndEndTimeForYM(Date date) {
        LocalDate localDate = dateToLocalDate(date);
        String[] beginAndEndDate = new String[2];
        int month = localDate.getMonthValue();
        switch (month % 3) {
            case 1:
                beginAndEndDate[0] = localDate.format(FORMATTER_YM).toString();
                beginAndEndDate[1] = localDate.plusMonths(2).format(FORMATTER_YM).toString();
                break;
            case 2:
                beginAndEndDate[0] = localDate.minusMonths(1).format(FORMATTER_YM).toString();
                beginAndEndDate[1] = localDate.plusMonths(1).format(FORMATTER_YM).toString();
                break;
            default:
                beginAndEndDate[0] = localDate.format(FORMATTER_YM).toString();
                beginAndEndDate[0] = localDate.minusMonths(2).format(FORMATTER_YM).toString();
                break;
        }
        return beginAndEndDate;
    }

    /**
     * 获取指定周的开始时间
     *
     * @param offset 0本周  1(n)下周  -1(n)上周
     * @return Date
     */
    public static LocalDate getFirstDayOfWeek(int offset) {
        LocalDate now = LocalDate.now().plusWeeks(offset);
        return now.with(DayOfWeek.MONDAY);
    }

    /**
     * 获取指定月的开始时间
     *
     * @param offset 0本月  1(n)下月 -1(n)上月
     * @return Date
     */
    public static LocalDate getFirstDayOfMonth(int offset) {
        LocalDate now = LocalDate.now().plusMonths(offset);
        return now.with(TemporalAdjusters.firstDayOfMonth());
    }


    /**
     * 获取指定月的结束时间
     *
     * @param offset 0本月  1(n)下月 -1(n)上月
     * @return Date
     */
    public static LocalDate getLastDayOfMonth(int offset) {
        LocalDate now = LocalDate.now().plusMonths(offset);
        return now.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 获取指定季度的开始时间
     *
     * @param offset 0本季度  1(n)下季度 -1(n)上季度
     * @return Date
     */
    public static LocalDate getFirstDayOfQuarter(int offset) {
        LocalDate now = LocalDate.now().plusMonths(offset * 3L);
        LocalDate firstDate = null;
        switch (now.getMonthValue() % 3) {
            case 0:
                firstDate = now.minusMonths(2);
            case 1:
                firstDate = now;
            case 2:
                firstDate = now.minusMonths(1);
        }
        return firstDate.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 获取指定年的开始时间
     *
     * @param offset 0年  1(n)下年 -1(n)上年
     * @return Date
     */
    public static LocalDate getFirstDayOfYeat(int offset) {
        LocalDate now = LocalDate.now().plusMonths(offset);
        return now.with(TemporalAdjusters.firstDayOfYear());
    }

    /**
     * 获取季度
     *
     * @param dateTime dateTime
     */
    public static int getQuarter(LocalDateTime dateTime) {
        return getQuarter(dateTime.getMonthValue());
    }

    /**
     * 获取季度
     *
     * @param dateTime dateTime
     */
    public static int getQuarter(LocalDate dateTime) {
        return getQuarter(dateTime.getMonthValue());
    }

    public static int getQuarter(int month) {
        if (month >= 1 && month < 4) {
            return 1;
        }
        if (month >= 4 && month < 7) {
            return 2;
        }
        if (month >= 7 && month < 10) {
            return 3;
        }
        if (month >= 10 && month < 12) {
            return 4;
        }
        return 0;
    }

    /**
     * 获取周里每一天
     */
    public static List<String> getWeekOfDay() {
        return IntStream.rangeClosed(1, 7).mapToObj(String::valueOf).collect(Collectors.toList());
    }

    /**
     * 获取截止到当前月里每一天
     */
    public static List<String> getMonthOfDay() {
        LocalDate now = LocalDate.now();
        LocalDate first = now.with(TemporalAdjusters.firstDayOfMonth());
        int last = now.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        return IntStream.range(0, last).mapToObj(i -> first.plusDays(i).format(FORMATTER_MD)).collect(Collectors.toList());
    }

    /**
     * 获取指定月里每一天
     */
    public static List<String> getMonthOfDay(LocalDate time) {
        int first = time.with(TemporalAdjusters.firstDayOfMonth()).getDayOfMonth();
        int last = time.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        return IntStream.rangeClosed(first, last).mapToObj(String::valueOf).collect(Collectors.toList());
    }

    /**
     * 获取指定月里每一天
     */
    public static List<String> getMonthOfDay(String time) {
        LocalDate localDate = stringToLocalDate(time);
        LocalDate first = localDate.with(TemporalAdjusters.firstDayOfMonth());
        int last = localDate.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
        return IntStream.range(0, last).mapToObj(i -> first.plusDays(i).format(FORMATTER_MD)).collect(Collectors.toList());
    }

    /**
     * 获取当前年里每一季
     */
    public static List<String> getQuarterOfYear() {
        return IntStream.rangeClosed(1, 4).mapToObj(String::valueOf).collect(Collectors.toList());
    }

    /**
     * 获取当前年里每一月
     */
    public static List<String> getMonthOfYear() {
        return IntStream.rangeClosed(1, 12).mapToObj(String::valueOf).collect(Collectors.toList());
    }

    /**
     * 获取当前年里每一周
     */
    public static List<String> getWeekOfYear() {
        return IntStream.rangeClosed(1, 52).mapToObj(String::valueOf).collect(Collectors.toList());
    }


    public static LocalDate getStartDate(Integer type) {
        LocalDate startDate = null;
        switch (type) {
            case 1:
                startDate = getFirstDayOfWeek(0);
                break;
            case 2:
                startDate = getFirstDayOfMonth(0);
                break;
            case 3:
                startDate = getFirstDayOfQuarter(0);
                break;
            case 4:
                startDate = getFirstDayOfYeat(0);
                break;
            default:
                startDate = getFirstDayOfYeat(0);
                break;
        }
        return startDate;
    }

    /**
     * 获取季度
     * 格式：2019-1（季度）
     *
     * @param time time
     * @return Date
     */
    public static String getQuarterOfYearMult(LocalDate time) {
        int quarter = getQuarter(time);
        return time.getYear() + "-" + quarter;
    }

    /**
     * 获取季度
     * 格式：2019-1(月)
     *
     * @param time time
     * @return Date
     */
    public static String getMonthOfYearMult(LocalDate time) {
        return time.getYear() + "-" + time.getMonthValue();
    }

    /**
     * 获取指定日期到现在的所有月
     *
     * @param startDate startDate
     * @return Date
     */
    public static List<String> getMonthOfYearBySpecific(LocalDate startDate) {
        LocalDate now = LocalDate.now().minusMonths(1);
        int nowYear = now.getYear();
        int startYear = startDate.getYear();
        List<String> list = new ArrayList<>();
        int diff = nowYear - startYear;
        for (int i = diff; i >= 0; i--) {
            List<String> x = new ArrayList<>();
            LocalDate after = startDate.plusYears(i);
            if (after.getYear() == nowYear) {
                x = IntStream.rangeClosed(1, now.getMonthValue()).mapToObj(n -> after.getYear() + "-" + n).collect(Collectors.toList());
            } else if (after.getYear() == startYear) {
                x = IntStream.rangeClosed(after.getMonthValue(), 12).mapToObj(n -> after.getYear() + "-" + n).collect(Collectors.toList());
            } else {
                x = IntStream.rangeClosed(1, 12).mapToObj(n -> after.getYear() + "-" + n).collect(Collectors.toList());
            }
            list.addAll(x);
        }
        return list;
    }

    /**
     * 获取指定日期到现在所有季度
     *
     * @param startDate startDate
     * @return Date
     */
    public static List<String> getQuarterOfYearBySpecific(LocalDate startDate) {
        LocalDate now = LocalDate.now();
        int nowYear = now.getYear();
        int startYear = startDate.getYear();
        List<String> list = new ArrayList<>();
        int diff = nowYear - startYear;
        for (int i = diff; i >= 0; i--) {
            List<String> x = new ArrayList<>();
            LocalDate after = startDate.plusYears(i);
            if (after.getYear() == nowYear) {
                x = IntStream.rangeClosed(1, getQuarter(now) - 1).mapToObj(n -> after.getYear() + "-" + n).collect(Collectors.toList());
            } else if (after.getYear() == startYear) {
                x = IntStream.rangeClosed(getQuarter(after), 4).mapToObj(n -> after.getYear() + "-" + n).collect(Collectors.toList());
            } else {
                x = IntStream.rangeClosed(1, 4).mapToObj(n -> after.getYear() + "-" + n).collect(Collectors.toList());
            }
            list.addAll(x);
        }
        return list;
    }

    /**
     * 当前时间向前推n天,不包含当天
     * @param offset offset
     * @return Date
     */
    public static List<String> beforDays(int offset){
        LocalDate date = LocalDate.now().minusDays(offset + 1);
        return IntStream.rangeClosed(1,offset).mapToObj(i -> date.plusDays(i).format(FORMATTER_MD)).collect(Collectors.toList());
    }

    /**
     * 将短时间格式时间转换为字符串 yyyy-MM-dd
     *
     * @param dateDate date
     * @return Date
     */
    public static String dateToStr(Date dateDate) {
        String dateString = new SimpleDateFormat(YEAR_MONTH_DAY).format(dateDate);
        return dateString;
    }


    public static String dateToStr(LocalDate dateDate) {
        String dateString = FORMATTER_YMD.format(dateDate);
        return dateString;
    }
    /**
     * 获取现在时间
     *
     * @return Date 返回时间类型 yyyy-MM-dd HH:mm:ss
     */
    public static Date getNowDate() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(new Date());
        ParsePosition pos = new ParsePosition(8);
        Date currenttime2 = formatter.parse(dateString, pos);
        return currenttime2;
    }

    /**
     * 将短时间格式字符串转换为时间 yyyy-MM-dd
     *
     * @param strDate strDate
     * @return Date
     */
    public static Date strToDate(String strDate) {
        ParsePosition pos = new ParsePosition(0);
        Date strtodate = new SimpleDateFormat(YEAR_MONTH_DAY).parse(strDate, pos);
        return strtodate;
    }
}
